import 'dotenv/config';
import net from 'net';
import express from 'express';
import mongoose from 'mongoose';
import http from 'http';
import { Server } from 'socket.io';
import cors from 'cors';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// WGS84 转 GCJ02
function transformFromWGSToGCJ(wgsLat, wgsLon) {
  const pi = 3.14159265358979324;
  const a = 6378245.0;
  const ee = 0.00669342162296594323;

  function transformLat(x, y) {
    let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
    return ret;
  }

  function transformLon(x, y) {
    let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
    return ret;
  }

  let dLat = transformLat(wgsLon - 105.0, wgsLat - 35.0);
  let dLon = transformLon(wgsLon - 105.0, wgsLat - 35.0);
  let radLat = wgsLat / 180.0 * pi;
  let magic = Math.sin(radLat);
  magic = 1 - ee * magic * magic;
  let sqrtMagic = Math.sqrt(magic);
  dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
  dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
  
  return {
    latitude: wgsLat + dLat,
    longitude: wgsLon + dLon
  };
}

// 环境变量配置
const TCP_PORT = process.env.TCP_PORT || 9998;
const WEB_PORT = process.env.PORT || 9999;
const MONGO_URI = process.env.MONGODB_URI;

// 连接MongoDB数据库
let dbConnected = false;

mongoose.connect(MONGO_URI, {
  serverSelectionTimeoutMS: 30000, // 增加超时时间到30秒
  socketTimeoutMS: 45000, // 套接字超时
}).then(() => {
  console.log('MongoDB连接成功');
  dbConnected = true;
}).catch(err => {
  console.error('MongoDB连接失败:', err);
  console.log('系统将继续运行，但不会保存位置数据到数据库');
});

// 定义用户模型
const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  amapKey: { type: String, required: true },
  securityJsCode: { type: String, required: true },  // 添加安全密钥字段
  createdAt: { type: Date, default: Date.now },
  updatedAt: { type: Date, default: Date.now }
});

const User = mongoose.model('User', userSchema);

// 定义坐标数据模型
const locationSchema = new mongoose.Schema({
  // 用户信息
  username: { type: String, required: true, index: true },
  // GCJ02坐标（高德地图使用）
  latitude: { type: Number, required: true },
  longitude: { type: Number, required: true },
  // 原始WGS84坐标
  wgs84: {
    latitude: { type: Number, required: true },
    longitude: { type: Number, required: true }
  },
  timestamp: { type: Date, default: Date.now }
});

const Location = mongoose.model('Location', locationSchema);

// 创建TCP服务器
const tcpServer = net.createServer((socket) => {
  const clientAddress = `${socket.remoteAddress}:${socket.remotePort}`;
  console.log(`TCP客户端已连接: ${clientAddress}`);
  
  // 发送连接事件到WebSocket
  io.emit('tcpClientConnected', {
    address: clientAddress,
    time: new Date().toISOString(),
    status: 'connected'
  });
  
  let username = null; // 存储当前连接的用户名
  
  socket.on('data', async (data) => {
    const dataStr = data.toString().trim();
    console.log('接收到数据:', dataStr);

    // 发送数据事件到WebSocket
    io.emit('tcpClientData', {
      address: clientAddress,
      data: dataStr,
      time: new Date().toISOString()
    });

    try {
      // 解析数据格式：username|longitude,latitude
      const [userInfo, coordinates] = dataStr.split('|');
      if (!userInfo || !coordinates) {
        throw new Error('数据格式错误，应为：username|longitude,latitude');
      }

      username = userInfo;
      const [wgsLon, wgsLat] = coordinates.split(',').map(Number);

        if (!isNaN(wgsLat) && !isNaN(wgsLon)) {
          // 转换为高德坐标系
          const gcj02Coords = transformFromWGSToGCJ(wgsLat, wgsLon);
          console.log('WGS84坐标:', { latitude: wgsLat, longitude: wgsLon });
          console.log('转换后的GCJ02坐标:', gcj02Coords);

          // 只有在数据库连接成功时才保存数据
          if (dbConnected) {
            try {
              // 保存原始WGS84坐标和转换后的GCJ02坐标到数据库
              // 创建东八区的时间戳（UTC+8）
              const chinaTime = new Date();
              // 调整为东八区时间（加8小时）
              chinaTime.setHours(chinaTime.getHours() + 8);
              
              const location = new Location({
              username,
                // GCJ02坐标
                latitude: gcj02Coords.latitude,
                longitude: gcj02Coords.longitude,
                // 原始WGS84坐标
                wgs84: {
                  latitude: wgsLat,
                  longitude: wgsLon
                },
                // 使用东八区时间
                timestamp: chinaTime
              });

              await location.save();
              console.log('使用东八区时间保存坐标:', chinaTime.toISOString());
              console.log('坐标已保存:', {
              username,
                gcj02: gcj02Coords,
                wgs84: { latitude: wgsLat, longitude: wgsLon }
              });
            } catch (saveErr) {
              console.error('保存坐标失败:', saveErr);
            }
          }

          // 通过WebSocket广播新位置（使用转换后的坐标）
        io.to(username).emit('newLocation', { 
          username,
            latitude: gcj02Coords.latitude, 
            longitude: gcj02Coords.longitude,
            wgs84: {
              latitude: wgsLat,
              longitude: wgsLon
            },
            timestamp: new Date() 
          });
      }
    } catch (err) {
      console.error('处理数据失败:', err);
      // 发送错误事件到WebSocket
      io.emit('tcpClientError', {
        address: clientAddress,
        error: err.message,
        time: new Date().toISOString()
      });
    }
  });
  
  socket.on('end', () => {
    console.log(`客户端 ${username || clientAddress} 已断开连接`);
    // 发送断开连接事件到WebSocket
    io.emit('tcpClientDisconnected', {
      address: clientAddress,
      username: username,
      time: new Date().toISOString(),
      status: 'disconnected'
    });
  });
  
  socket.on('error', (err) => {
    console.error(`TCP连接错误 (${username || clientAddress}):`, err);
    // 发送错误事件到WebSocket
    io.emit('tcpClientError', {
      address: clientAddress,
      username: username,
      error: err.message,
      time: new Date().toISOString()
    });
  });
});

// 创建Express应用
const app = express();
app.use(cors());
app.use(express.json());

// 静态文件服务
if (process.env.NODE_ENV === 'production') {
  // 生产环境使用dist目录
  app.use(express.static(path.join(__dirname, 'dist')));
} else {
  // 开发环境不需要静态文件服务，由Vite开发服务器提供
  console.log('开发环境：静态文件由Vite服务');
}

// API路由
// 用户注册
app.post('/api/register', async (req, res) => {
  try {
    const { username, password, amapKey, securityJsCode } = req.body;
    
    // 检查用户是否已存在
    const existingUser = await User.findOne({ username });
    if (existingUser) {
      return res.status(400).json({ error: '用户名已存在' });
    }

    // 创建新用户
    const user = new User({
      username,
      password, // 实际应用中应该加密存储
      amapKey,
      securityJsCode // 添加安全密钥字段
    });

    await user.save();
    res.json({ message: '注册成功' });
  } catch (error) {
    console.error('注册失败:', error);
    res.status(500).json({ error: '注册失败' });
  }
});

// 用户登录
app.post('/api/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    
    const user = await User.findOne({ username });
    if (!user || user.password !== password) {
      return res.status(401).json({ error: '用户名或密码错误' });
    }

  res.json({
      username: user.username,
      amapKey: user.amapKey
    });
  } catch (error) {
    res.status(500).json({ error: '登录失败' });
  }
});

// 获取位置数据
app.get('/api/locations', async (req, res) => {
  try {
    const { username, start, end } = req.query;
    console.log('接收到位置查询请求:', { username, start, end });
    
    if (!username) {
      console.log('缺少用户名参数');
      return res.status(400).json({ error: '缺少用户名参数' });
    }

    let query = { username };
    console.log('初始查询条件:', query);

    // 处理时间范围
    query.timestamp = {};
    
    // 如果指定了具体的开始/结束时间
    if (start || end) {
      if (start) {
        const startDate = new Date(start);
        if (isNaN(startDate.getTime())) {
          return res.status(400).json({ error: '开始时间格式无效' });
        }
        query.timestamp.$gte = startDate;
        console.log('指定开始时间:', startDate.toISOString());
      }
      if (end) {
        // 为结束日期添加一天的时间，确保包含当天的所有数据
        const endDate = new Date(end);
        if (isNaN(endDate.getTime())) {
          return res.status(400).json({ error: '结束时间格式无效' });
        }
        // 将结束时间设为当天的23:59:59.999
        endDate.setHours(23, 59, 59, 999);
        query.timestamp.$lte = endDate;
        console.log('指定结束时间:', endDate.toISOString());
      }
    } 
    // 默认查询最近24小时
    else {
      const now = new Date();
      const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
      query.timestamp.$gte = oneDayAgo;
      query.timestamp.$lte = now;
      console.log('默认查询最近24小时:', {
        from: oneDayAgo.toISOString(),
        to: now.toISOString()
      });
    }

    console.log('最终查询条件:', JSON.stringify(query, null, 2));
    const locations = await Location.find(query)
      .sort({ timestamp: 1 })
      .lean()
      .exec();

    console.log(`查询结果: 找到 ${locations.length} 条记录`);
    if (locations.length === 0) {
      console.log('没有找到匹配的记录');
      
      // 查询所有时间范围内的记录，帮助调试
      const allLocations = await Location.find({ username })
        .sort({ timestamp: 1 })
        .lean()
        .exec();
      
      if (allLocations.length > 0) {
        console.log(`用户 ${username} 共有 ${allLocations.length} 条记录`);
        console.log('最早记录时间:', allLocations[0].timestamp);
        console.log('最晚记录时间:', allLocations[allLocations.length - 1].timestamp);
      } else {
        console.log(`用户 ${username} 没有任何记录`);
      }
    } else {
      console.log('第一条记录:', locations[0]);
      console.log('最后一条记录:', locations[locations.length - 1]);
    }

    res.json(locations);
  } catch (error) {
    console.error('获取位置数据失败:', error);
    res.status(500).json({ error: '获取位置数据失败: ' + error.message });
  }
});

// 添加用户信息更新路由
app.put('/api/user/update', async (req, res) => {
  try {
    const { username, currentPassword, newPassword, amapKey, securityJsCode } = req.body;
    
    // 查找用户
    const user = await User.findOne({ username });
    if (!user) {
      return res.status(404).json({ error: '用户不存在' });
    }

    // 验证当前密码
    if (currentPassword && currentPassword !== user.password) {
      return res.status(401).json({ error: '当前密码错误' });
    }

    // 更新用户信息
    const updates = {
      updatedAt: new Date()
    };

    if (newPassword) updates.password = newPassword;
    if (amapKey) updates.amapKey = amapKey;
    if (securityJsCode) updates.securityJsCode = securityJsCode;

    const updatedUser = await User.findOneAndUpdate(
      { username },
      updates,
      { new: true, select: '-password' }
    );

    res.json(updatedUser);
  } catch (error) {
    console.error('更新用户信息失败:', error);
    res.status(500).json({ error: '更新用户信息失败' });
  }
});

// 添加坐标测试接口
app.post('/api/test/location', async (req, res) => {
  try {
    const { username, longitude, latitude } = req.body;

    if (!username || !longitude || !latitude) {
      return res.status(400).json({ error: '缺少必要参数' });
    }

    // 验证坐标范围
    const lon = parseFloat(longitude);
    const lat = parseFloat(latitude);

    if (isNaN(lon) || isNaN(lat)) {
      return res.status(400).json({ error: '坐标必须是有效的数字' });
    }

    if (lon < -180 || lon > 180) {
      return res.status(400).json({ error: '经度必须在 -180 到 180 之间' });
    }

    if (lat < -90 || lat > 90) {
      return res.status(400).json({ error: '纬度必须在 -90 到 90 之间' });
    }

    // 转换为高德坐标系
    const gcj02Coords = transformFromWGSToGCJ(lat, lon);

    // 创建测试数据字符串，模拟TCP客户端发送的数据
    const testDataStr = `${username}|${lon},${lat}`;
    console.log('测试接口模拟TCP数据:', testDataStr);
    
    // 发送数据事件到WebSocket，模拟TCP客户端数据
    io.emit('tcpClientData', {
      address: 'API测试',
      data: testDataStr,
      time: new Date().toISOString()
    });

    // 保存到数据库
    if (dbConnected) {
      try {
        // 创建东八区的时间戳（UTC+8）
        const chinaTime = new Date();
        // 调整为东八区时间（加8小时）
        chinaTime.setHours(chinaTime.getHours() + 8);
        
        const location = new Location({
          username,
          latitude: gcj02Coords.latitude,
          longitude: gcj02Coords.longitude,
          wgs84: {
            latitude: lat,
            longitude: lon
          },
          // 使用东八区时间
          timestamp: chinaTime
        });

        await location.save();
        console.log('测试接口：使用东八区时间保存坐标:', chinaTime.toISOString());
      } catch (saveErr) {
        console.error('保存坐标失败:', saveErr);
      }
    }

    // 通过WebSocket广播新位置
    const locationData = {
      username,
      latitude: gcj02Coords.latitude,
      longitude: gcj02Coords.longitude,
      wgs84: {
        latitude: lat,
        longitude: lon
      },
      timestamp: new Date()
    };
    
    // 发送到用户房间
    io.to(username).emit('newLocation', locationData);
    
    // 同时全局广播，确保所有客户端都能收到
    io.emit('newLocation', locationData);

    res.json({ message: '坐标发送成功' });
  } catch (error) {
    console.error('处理测试坐标失败:', error);
    res.status(500).json({ error: '处理坐标失败' });
  }
});

// 处理前端路由
if (process.env.NODE_ENV === 'production') {
  app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, 'dist', 'index.html'));
  });
}

// 创建HTTP服务器
const server = http.createServer(app);

// 设置Socket.IO
const io = new Server(server, {
  cors: {
    origin: '*',
    methods: ['GET', 'POST'],
    credentials: true
  },
  path: '/socket.io',
  transports: ['websocket', 'polling'],
  allowEIO3: true,
  pingTimeout: 60000,
  pingInterval: 25000
});

io.on('connection', (socket) => {
  console.log('WebSocket客户端已连接');
  
  // 处理用户加入房间
  socket.on('join', (username) => {
    if (username) {
      console.log(`用户 ${username} 加入房间`);
      socket.join(username);
      
      // 发送确认消息
      socket.emit('joined', { 
        status: 'success', 
        message: `已加入房间: ${username}`,
        username: username
      });
    }
  });
  
  socket.on('disconnect', () => {
    console.log('WebSocket客户端已断开连接');
  });

  socket.on('error', (error) => {
    console.error('WebSocket错误:', error);
  });
});

// 启动服务器
tcpServer.listen(TCP_PORT, () => {
  console.log(`TCP服务器已启动，监听端口 ${TCP_PORT}`);
});

server.listen(WEB_PORT, () => {
  console.log(`Web服务器已启动，访问 http://localhost:${WEB_PORT}`);
});